package ar.uba.fi.tonyvaliente.signature.files;

import java.util.BitSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import ar.uba.fi.tonyvaliente.documents.Index;
import ar.uba.fi.tonyvaliente.documents.exception.QueryException;
import ar.uba.fi.tonyvaliente.files.File;
import ar.uba.fi.tonyvaliente.files.FileException;
import ar.uba.fi.tonyvaliente.persistors.BitSetPersistor;
import ar.uba.fi.tonyvaliente.persistors.IntegerPersistor;
import ar.uba.fi.tonyvaliente.signature.HashFunction;
import ar.uba.fi.tonyvaliente.signature.query.QueryDocuments;
import ar.uba.fi.tonyvaliente.signature.query.SignatureQueryException;
import ar.uba.fi.tonyvaliente.tree.BTreeException;
import ar.uba.fi.tonyvaliente.tree.DiskBTree;
import ar.uba.fi.tonyvaliente.utils.Pair;
import ar.uba.fi.tonyvaliente.utils.RecursosAplicacion;
import ar.uba.fi.tonyvaliente.utils.io.ByteCompletionMode;

public class SignatureIndex extends Index {

	private static final String DOCS_ROOT = RecursosAplicacion.instance().getProperty("docs.root");
	private static final String defaultIndexPath = DOCS_ROOT + "/document_hash_signature.data";
	private static final String defaultListsPath = DOCS_ROOT + "/document_lists.data";
	private String indexPath;
	private String listsPath;
	DiskBTree<Integer, BitSet> indexPersistence;
	private int hashLength;
//	TermListFileWrapper termListFileWrapper;
	private List<HashFunction> hashFunctions;
	private QueryDocuments queryDocuments;
	
	
	public SignatureIndex(List<HashFunction> hashFunctions, int hashLength, String indexPath, String listPath){
		this.hashFunctions = hashFunctions;
		this.hashLength = hashLength;
		this.indexPath = indexPath;
		this.listsPath = listPath;
	}
	
	public SignatureIndex(List<HashFunction> hashFunctions, int hashLength){
		this(hashFunctions, hashLength, defaultIndexPath, defaultListsPath);
	}
	
	@Override
	public void add(Object docSignature, int documentId) throws SignatureIndexException {

		BitSet signature = (BitSet) docSignature;
		try {
			indexPersistence.add(documentId, signature);
		} catch (BTreeException e) {
			throw new SignatureIndexException("Error agregando un documento al índice", e);
		}
		
	}

	@Override
	public void close() {

//		if (termListFileWrapper == null)
//			return;

		try {
//			termListFileWrapper.close();
			indexPersistence.close();
//		} catch (DocumentIndexException e) {
			// TODO Auto-generated catch block
//			e.printStackTrace();
		} catch (BTreeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public List<Integer> getDocuments(String term) throws QueryException {
		
		List<Integer> documentos;
		queryDocuments = new QueryDocuments(this.hashFunctions, this.hashLength, this.indexPersistence);
		try {
			documentos = queryDocuments.query(term);
		} catch (SignatureQueryException e) {
			throw new QueryException("Se produjo un error consultando los documentos", e);
		} 
		
		return documentos;
	}

	/*@Override
	public Iterator<String> getTermsIterator() {
		// TODO Auto-generated method stub
		return null;
	}*/

	@Override
	public void initialize(int keys) {
		ensureDelete();
		try {
			indexPersistence = new DiskBTree<Integer, BitSet>(keys,
					indexPath, new IntegerPersistor(),
					new BitSetPersistor(ByteCompletionMode.ONE_AND_TRAILING_ZEROS));

			queryDocuments = new QueryDocuments(hashFunctions, hashLength, indexPersistence);
			File listPersistence = File.create(listsPath, 8192);
//			termListFileWrapper = new TermListFileWrapper(listPersistence);
		} catch (BTreeException e) {
			e.printStackTrace();
		} catch (FileException e) {
			e.printStackTrace();
		}

	}

	@Override
	public void open() {

		if (indexPersistence != null)
			return;

		try {
			indexPersistence = new DiskBTree<Integer, BitSet>(
					indexPath, false, new IntegerPersistor(),
					new BitSetPersistor(ByteCompletionMode.ONE_AND_TRAILING_ZEROS));

			File listPersistence = File.open(listsPath, false);
//			termListFileWrapper = new TermListFileWrapper(listPersistence);
		} catch (BTreeException e) {
			e.printStackTrace();
		} catch (FileException e) {
			e.printStackTrace();
		}
	}
	
	
	public Iterator<Pair<Integer, BitSet>> getIndexElementIterator() {
		return this.indexPersistence.iterator();
	}



	private void ensureDelete() {
		java.io.File file = new java.io.File(indexPath);
		if (file.exists()) {
			file.delete();
		}

		file = new java.io.File(listsPath);
		if (file.exists()) {
			file.delete();
		}
	}

	private void ensurePersistence() {
		if (indexPersistence != null)
			return;
		open();
	}
}
